/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 battlefield.h

	$Header: /heroes4/battlefield.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( BATTLEFIELD_H_INCLUDED )
#define BATTLEFIELD_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "abstract_combat_object.h"
#include "ai_combat_data_cache.h"
#include "animation_ptr.h"
#include "attack.h"
#include "attack_angle.h"
#include "battlefield_cell.h"
#include "battlefield_preset_map_in_game.h"
#include "bitmap_cursor.h"
#include "castle_gate_ptr.h"
#include "combat_action_message.h"
#include "combat_area_shader_ptr.h"
#include "combat_creature.h"
#include "combat_creature_handler.h"
#include "combat_spell_ptr.h"
#include "combat_user_action_ptr.h"
#include "combat_path_finder_ptr.h"
#include "compound_object_model_ptr.h"
#include "compound_object_ptr.h"
#include "idle_processor.h"
#include "isometric_map.h"
#include "map_point_list.h"
#include "missile_handler.h"
#include "move_missile_ptr.h"
#include "point_2d.h"
#include "quad.h"
#include "rational.h"
#include "sequence_loader.h"
#include "shared_ptr.h"
#include "timed_callback.h"
#include "timed_window_ptr.h"
#include "uncopyable.h"
#include "window_handler.h"

class	t_abstract_grail_data_source;
class	t_attackable_object;
class	t_attackable_obstacle;
class	t_battlefield_terrain_map;
class	t_battlefield_window;
class	t_button;
class	t_cached_grail_data_source;
class	t_combat_actor;
class	t_combat_castle;
class	t_combat_context;
enum	t_combat_cursor_mode;
class	t_combat_flinch;
class	t_combat_object_model_cache;
class	t_combat_path;
struct	t_combat_path_data;
class	t_combat_window;
class	t_counted_animation;
class	t_creature_array;
enum	t_difficulty;
struct t_map_point_2d;
struct t_map_point_3d;
enum   t_missile_type;
class  t_combat_non_blocking_message_displayer;
class  t_ownable_garrisonable_adv_object;
class  t_play_combat_animation;
struct t_screen_point;
class  t_stationary_combat_object;
enum   t_combat_actor_action_id;
class  t_combat_path_finder;
enum   t_direction;
struct t_pixel_24;
class  t_player;
enum   t_player_color;
enum   t_spell;
class  t_town;
enum   t_town_image_level;
class  t_window;

enum t_wall_bonus
{
	k_wall_bonus_none,
	k_wall_bonus_attack,
	k_wall_bonus_defense
};

enum t_ranged_result
{
	k_ranged_result_normal,
	k_ranged_result_obscured,
	k_ranged_result_blocked
};

enum t_message_icon
{
	k_message_icon_none = -1,

	k_message_icon_damage,
	k_message_icon_death,
	k_message_icon_heal,
	k_message_icon_stoned,
	k_message_icon_angel,
	k_message_icon_spell_points,
	k_message_icon_good_luck,
	k_message_icon_bad_luck,
	k_message_icon_shield,

	k_message_icon_count
};

enum t_combat_state
{
	k_combat_state_selecting_creature,
	k_combat_state_choosing_action,	
	k_combat_state_awaiting_human_order,	
	k_combat_state_awaiting_ai_order,
	k_combat_state_action_begun,
	k_combat_state_finished,			// combat finished, not just an action
};

int const k_wall_safe_distance = 3;
int const k_ranged_area_attack_radius = 5 * k_battlefield_subcells_per_cell;
	


typedef std::list<t_attackable_object*>						t_attackable_object_list;
typedef t_counted_ptr<t_attackable_obstacle>				t_attackable_obstacle_ptr;
typedef std::list<t_attackable_obstacle_ptr>				t_attackable_obstacle_list;
typedef std::vector<t_combat_object_model_cache>			t_combat_object_model_cache_array;
typedef std::list<t_counted_animation*>						t_counted_animation_list;
typedef t_counted_ptr<t_stationary_combat_object>			t_stationary_combat_object_ptr;
typedef std::list<t_stationary_combat_object_ptr>			t_stationary_combat_object_list;
typedef t_stationary_combat_object_list::iterator			t_stationary_combat_object_iterator;
typedef t_stationary_combat_object_list::const_iterator		t_stationary_combat_object_const_iterator;
typedef std::list<t_timed_window_ptr>						t_timed_window_list;

// -----------------------------------------------------------------------
// t_battlefield class
// -----------------------------------------------------------------------
class t_battlefield : public t_counted_object, private t_uncopyable, public t_idle_processor
{
public:

	// Types
	typedef t_combat_actor							t_actor;
	typedef t_counted_ptr< t_actor >				t_actor_ptr;
	typedef t_counted_ptr< t_combat_creature >      t_creature_ptr;
	typedef t_counted_const_ptr< t_combat_creature > t_creature_const_ptr;
	typedef t_battlefield_cell						t_cell;
	typedef t_battlefield_cell_vertex				t_cell_vertex;
	typedef t_quad< t_cell_vertex & >				t_cell_vertex_quad;
	typedef t_quad< t_cell_vertex const & >			t_const_cell_vertex_quad;

	typedef t_abstract_combat_object				t_object;
	typedef t_combat_object_ptr						t_object_ptr;
	typedef t_combat_object_iterator				t_object_iterator;
	typedef t_combat_object_const_iterator			t_object_const_iterator;

	typedef t_combat_creature_list	                t_creature_list;

	typedef std::list< t_object_ptr >				t_object_ptr_list;
	typedef t_stationary_combat_object				t_stationary_object;
	typedef t_counted_ptr< t_stationary_object >	t_stationary_object_ptr;

	class t_missile_strike_data
	{
		public:
			t_missile_strike_data( bool physical_attack, t_combat_action_message const & message );

			bool							get_is_physical_attack() const;
			t_combat_action_message const & get_message() const;

		private:
			bool					m_physical_attack;
			t_combat_action_message m_message;
	};

	class t_end_damage_spell_data
	{
		public:
			t_end_damage_spell_data( t_combat_creature * creature, t_spell spell, t_combat_action_message const & message );

			t_combat_creature *				get_creature() const;
			t_spell							get_spell() const;
			t_combat_action_message const & get_message() const;
		private:
			t_combat_creature *		m_creature;
			t_spell					m_spell;
			t_combat_action_message m_message;
	};



	// Constructor
	t_battlefield( t_creature_array* attacker, t_creature_array* defender );
	t_battlefield( t_combat_context&				context,
				   t_screen_point const&			view_size, 
		           t_battlefield_terrain_map&		terrain_map, 
				   t_combat_window *				window,
				   t_preset_battle_map_array const&	battlefield_preset_map_vector,
				   bool								at_sea );
	virtual ~t_battlefield();

	// Member functions
	void                        add( t_combat_creature* actor );
	void						added( t_attackable_obstacle* obstacle );
	void                        add_action( t_handler handler, bool to_front = false );
	void                        add_attack( t_combat_creature*				attacker,
		                                    t_attackable_object*			defender,
											bool							ranged, 
											t_combat_action_message const & message );
	void						add_creature_label( t_abstract_combat_object* object );
	void						add_damage_text( t_combat_creature const&	creature,
												 int						damage,
												 int						deaths );
	void						add_drift_window( t_timed_window* timed_window );
	void						add_gate( t_stationary_combat_object* object );
	void						add_prompt( t_combat_creature& creature,
		                                    std::string const& text );
	void					    add_text( t_abstract_combat_object& creature,
	                                      std::string const& text,
							              t_pixel_24 const&  color,
										  t_message_icon	 icon_id = k_message_icon_none );
	void                        add_threat( t_combat_creature* actor );
	void						add_viewer( t_battlefield_window * new_viewer_ptr );
	static void					adjust_for_charging_bonus(int &damage, int distance_moved);
	void						animation_ended( t_counted_animation* animation );
	void						animation_started( t_counted_animation* animation );
	t_abstract_combat_object*	attackable_hit_test( t_screen_point const& screen_point ) const;
	void                        begin_action( bool cancel_sanctuary = true );
	void                        begin_attack( t_combat_creature& target );
	bool					    begin_move( t_map_point_2d const& point );
	bool					    begin_move( t_map_point_2d const& point, 
							                t_combat_creature_handler handler );
	bool						begin_move( t_combat_creature&				creature,
											t_combat_path&			        path,
											t_map_point_2d const&	        point, 
											t_combat_creature_handler       handler,
											t_combat_action_message const & message = t_combat_action_message() );
	void					    begin_ranged_attack( t_combat_creature* 	  target );
	void						begin_ranged_attack( t_map_point_2d const& target );
	void                        begin_spell( t_map_point_2d const& target );
	void                        begin_spell( t_combat_creature const* target );
	void					    begin_spell( t_combat_creature const*		 target,	// Used only by mana_leech "pseudo-spell"
								             t_combat_creature_handler		 handler,
											 t_combat_creature_handler		 end_handler,
											 t_combat_action_message const & message );
	int							calculate_surrender_cost( bool side ) const;
	bool						can_place( t_map_point_2d const& point, 
		                                   int footprint_size ) const;
	bool                        can_place( t_combat_object_base const& object, 
		                                   t_map_point_2d const&	   point ) const;
	bool						can_place( t_combat_object_base const&		object, 
										   t_map_point_2d const&			point,
										   t_abstract_combat_object const*	ignored_object ) const;
	bool						can_retreat( bool side, std::string* help_text = 0 ) const;
	bool						can_see( t_combat_creature const& attacker, 
										 t_combat_creature const& defender ) const;
	bool						can_see_subcell( t_combat_creature const& attacker, 
							                     t_map_point_2d const& sub_cell ) const;
	bool						can_see_subcell( t_combat_creature const& attacker, 
							                     t_map_point_2d const& sub_cell,
												 t_ranged_result &obscured) const;
	bool						can_see_cell( t_combat_creature const& attacker, 
							                  t_map_point_2d const& point ) const;
	bool						can_see_cell( t_combat_creature const& attacker, 
							                  t_map_point_2d const& point,
											  t_ranged_result &obscured) const;
	bool                        can_shoot( t_combat_creature const& creature ) const;
	bool						can_surrender( bool side, std::string* help_text = 0 ) const;
	void                        cancel_spell();
	void						cast_default_spell( t_screen_point const& screen_point );
	bool					    cast_spell( t_combat_creature const&		caster, 
							                t_combat_creature&				target,
								            t_spell							spell,
											t_combat_action_message const & message,
											int								power );
	t_stationary_combat_object_iterator			castle_begin();
	t_stationary_combat_object_const_iterator	castle_begin() const;
	t_stationary_combat_object_iterator			castle_end();
	t_stationary_combat_object_const_iterator	castle_end() const;
	void						change_model( t_combat_creature&					creature,
											  t_cached_ptr< t_combat_actor_model >	model );
	void						check_ranged_retaliation( t_combat_creature*        attacker,
										                  t_combat_creature*        defender );
	t_screen_point				cell_to_screen_point( t_map_point_2d const & point ) const;
	t_screen_point				cell_to_screen_point( t_map_point_3d const & point ) const;
	bool						cell_hit_test( t_screen_point const & point, 
		                                       t_map_point_2d & result ) const;
	void						check_gate_close();
	bool						check_resistance( t_combat_creature const& caster,
									              t_combat_creature&       target,
									              t_spell                  spell );
	t_map_point_3d				compute_label_position( t_abstract_combat_object const* label,
														t_map_point_3d const&			position ) const;
	int							compute_terrain_height( t_map_point_2d const & subcell_point ) const;
	int							compute_terrain_height( t_map_point_2d const& subcell,
		                                                t_map_point_2d const& footprint ) const;
   	int							compute_terrain_height_under_object(
										t_object const &		object,
										t_map_point_2d const &	subcell_point ) const;
	int							compute_terrain_height_under_object( t_object const& object ) const;
	t_combat_creature*          creature_hit_test( t_screen_point const& point ) const;
	t_combat_creature_iterator  creatures_begin();
	t_combat_creature_iterator  creatures_end();
	int							creatures_size() const;
	t_wall_bonus				crosses_wall( t_map_point_2d const& attacker_center,
											  t_map_point_2d const& defender_center ) const;
	t_wall_bonus				crosses_wall( t_combat_creature const&	 attacker,
								              t_attackable_object const& defender ) const;
	void                        cursor_mode_menu( t_button* );
	void                        defend();
	void                        end_animation( t_combat_creature& actor );
	void                        end_combat();
	void                        end_damage_spell( t_window* window,
		                                          t_end_damage_spell_data data );
	void                        end_spell( t_window* window, t_combat_creature& );
	void                        end_walk( t_combat_creature& actor );
	bool                        enemy_adjacent( t_combat_creature const& actor ) const;
	bool                        enemy_adjacent( t_combat_creature const& actor,
		                                        t_map_point_2d const& point ) const;
	t_town*						find_nearest_town( bool defender, 
												   bool & enemy_adjacent_towns_found,
												   bool & blocked_towns_found  ) const;
	t_combat_creature*			find_summoned_creature( t_spell spell, t_creature_type creature_type,
														bool side );
	bool						gate_is_blocked() const;
	bool						gate_is_open() const;
	t_combat_creature*          get_acting_creature() const;
	int							get_active_creature_count( bool side ) const;
	bool						get_acting_side() const;
	int						    get_area_range_factor(  t_combat_creature*	target, 
													    t_map_point_2d&		map_point,
														int					radius ) const;
	bool						get_area_range_target( t_combat_creature*	target,
													   t_map_point_2d&		map_point,
													   int					radius ) const;
	t_combat_creature_list	    get_area_targets( t_map_point_2d const& subcell, int radius ) const;
	t_creature_array**			get_armies();
	t_creature_array&			get_army( bool defender ) const;
	bool						get_attack_angle( t_screen_point		screen_point, 
					                              t_attackable_object*	target,
									              t_attack_angle&		result ) const;
	void					    get_attack_angles( const t_attackable_object&	target,
									               t_attack_angle_list&			result ) const;
	void						get_attack_angles( const t_combat_creature  &	attacker,
												   const t_attackable_object&	target,
												   t_attack_angle_list&			result ) const;
	int                         get_base_height() const;
	void						get_berserk_targets( t_combat_creature const&	creature,
													 t_combat_creature_list&	targets ) const;
	t_mouse_window*             get_blocked_cursor() const;
	t_combat_creature_list		get_breath_targets( t_combat_creature const&	attacker,
												    t_attackable_object const&	defender,
												    t_map_point_2d const&		attack_point,
												    t_map_point_2d const&		target_point,
												    bool						check_resistance ) const;
	t_town_image_level			get_castle_level() const;
	int							get_castle_row() const;
	double						get_castle_wall_bonus() const;
	t_cell &					get_cell( t_map_point_2d const & cell_point );
	t_cell const &				get_cell( t_map_point_2d const & cell_point ) const;
	t_map_point_3d				get_cell_center( t_map_point_2d const& cell_point ) const;
	int							get_cell_row_end( int row ) const;
	int							get_cell_row_start( int row ) const;
	t_cell_vertex &				get_cell_vertex( t_map_point_2d const & vertex_point );
	t_cell_vertex const &		get_cell_vertex( t_map_point_2d const & vertex_point ) const;
	t_cell_vertex_quad			get_cell_vertex_quad( t_map_point_2d const & cell_point );
	t_const_cell_vertex_quad	get_cell_vertex_quad( t_map_point_2d const & cell_point ) const;
	t_screen_point				get_cell_vertex_screen_point( t_map_point_2d const&	vertex_point ) const;
	t_combat_window*			get_combat_window() const;
	t_combat_creature*          get_creature( t_map_point_2d const& point ) const;
	t_creature_list				get_creatures_with_casualties( t_screen_point const& point,
															   bool					 attacker,
															   bool					 defender ) const;
	t_combat_path_finder&	    get_current_path_finder() const;
	t_combat_creature const *	get_current_movement_shaded_creature() const;
	t_ai_combat_data_cache &    get_data_cache() const;
	t_combat_spell*				get_default_spell() const;
	t_difficulty				get_difficulty() const;
	t_castle_gate_ptr			get_gate() const;
	t_map_point_2d				get_gate_position() const;
	t_map_rect_2d				get_gate_rect() const;
	t_abstract_grail_data_source const & get_grail_data( bool defender ) const;
	std::string                 get_help_text() const;
	// get angles for a given point where enemies impede an actor's movement.
	void                        get_impeded_angles( t_combat_creature const& actor,
		                                            t_map_point_2d const& point,
													bool*                 angles ) const;
	t_mouse_window*				get_info_cursor() const;
	t_rational_point            get_logical_point( t_screen_point const& point ) const;
	int							get_magic_dampener_bonus(bool for_defender) const;
	t_mouse_window*				get_melee_cursor( t_screen_point	   screen_point, 
												  t_attackable_object* target,
												  std::string&         help_text );
	double						get_model_scale() const;
	t_mouse_window*				get_move_cursor( t_map_point_2d const& point,
												 std::string& help_text );
	t_attackable_object_list	get_multi_attack_targets( t_combat_creature const&		attacker,
														  t_attackable_object const&	defender,
														  t_attack_angle const&			attack_angle );
	long						get_new_battlefield_id();
	t_mouse_window*			    get_new_cursor( t_screen_point screen_point );
	t_mouse_window*             get_normal_cursor() const;
	t_combat_path_data const&   get_path_point( t_map_point_2d const& point ) const;
	t_map_point_2d_list			get_placement_points( t_map_point_2d const& center,
													  t_combat_creature&    creature,
													  int                   distance_variance);
	t_player*					get_player( bool defender ) const;
	t_player_color              get_player_color(bool defender) const;
	t_player**					get_players();
	t_combat_cursor_mode		get_preferred_action() const;
	int        				    get_range_factor( t_combat_creature const& attacker,
		                                          t_combat_creature const& defender ) const;
	t_mouse_window*				get_ranged_cursor( t_combat_creature const* target, int factor,
												   std::string& help_text );
	t_combat_creature*			get_ranged_target( t_combat_creature const& attacker,
												   t_map_point_2d const&	defender_center,
												   t_ranged_result&			result,
												   bool                     ignore_other_creatures = false) const;
	t_combat_creature*          get_ranged_target( t_combat_creature const& attacker,
									               t_combat_creature const& target ) const;
	t_creature_list             get_resurrection_targets( t_screen_point const& point,
														  bool			        defender,
														  t_spell               spell ) const;
	int							get_retaliation_time_stamp() const;
	bool						get_retreat_checked( bool side ) const;
	int                         get_row_end( int row ) const;
	int                         get_row_start( int row ) const;
	int							get_size() const;
	t_mouse_window*             get_spell_cursor() const;
	t_animation_ptr             get_spell_cursor_animation() const;
	t_mouse_window*				get_spell_cannot_cast_cursor() const;
	t_combat_state				get_state() const;
	t_stationary_combat_object* get_tower( t_map_point_2d const& point,
		                                   t_combat_footprint const& footprint ) const;
	t_mouse_window*				get_tower_move_cursor() const;
	t_rational_point const&		get_view_ratio() const;
	t_screen_point const&		get_view_size() const;
	int							get_wall_thickness() const;
	t_battlefield_window*       get_window() const;
	bool						has_gate() const;
	void						initialize_cell_map(
										t_battlefield_terrain_map const & terrain_map );
	void						initialize_cell_vertex_map(
										t_battlefield_terrain_map const & terrain_map );
	void						invalidate( t_object& object ) const;
	bool						is_computer_controlled( bool defender ) const;
	bool                        is_computer_controlled( t_combat_creature const& creature ) const;
	bool						is_in_castle( t_map_point_2d const& point ) const;
	bool					    is_sea_battle() const;
	bool                        is_valid( t_map_point_2d const& point ) const;
	void						launch_missile( t_missile_type					missile_type,
												t_combat_creature&				source,
												t_map_point_3d const&			source_position,
												t_map_point_3d const&			end_position, 
												t_missile_handler				handler,
												t_combat_action_message const &	message );
	void					    left_button_down( t_screen_point const& screen_point );
	void                        left_click( t_screen_point const& screen_point );
	void						mark_gate( bool arg );
	void					    missile_impact( t_combat_creature&		defender, 
								                t_direction				defend_direction,
											    t_combat_creature_ptr	attacker,
												bool					physical_attack,
												t_combat_action_message message );
	void						missile_strike( t_combat_creature_ptr			attacker,
		                                        t_map_point_2d					cell,
												t_missile_strike_data			data );
	void						move_object( t_object& object,
										     t_map_point_2d const &		new_position );
	void						move_object( t_object&	object,
										     t_map_point_3d const &		new_position );
	void					    move_to_attack( t_abstract_combat_object* target, 
		                                        t_map_point_2d const& point );
	t_object_iterator			objects_begin();
	t_object_const_iterator		objects_begin() const;
	t_object_iterator			objects_end();
	t_object_const_iterator		objects_end() const;
	t_object_iterator			object_hit_test( t_uint32				current_time,
								 			     t_screen_point const&	screen_point );
	t_object_const_iterator		object_hit_test( t_uint32				current_time,
											     t_screen_point const &	screen_point ) const;
	bool						object_hit_test( t_object const&		  object,
									             t_uint32			  current_time,
									             t_screen_point const& point ) const;
	bool                        off_map( t_combat_object_base const& object, 
		                                 t_map_point_2d const&       point ) const;
	bool                        off_map( int footprint_size,
		                                 t_map_point_2d const&       point ) const;
	virtual void				on_idle();
	void						open_gate( t_handler end_handler );
	void                        open_spellbook( t_window* parent );
	void						place_object( t_object_ptr object_ptr,
											  t_map_point_2d const &	position );
	void						place_object( t_object_ptr			object_ptr,
											  t_map_point_3d const &	position );
	void						place_obstacle( t_combat_object_model_cache const&  cache,
		                                        t_map_point_2d const&				position );
	void                        preload( t_combat_actor&          creature, 
		                                 t_combat_actor_action_id action,
										 t_direction              direction );
	void					    preload_flinch( t_combat_creature& creature );
	void					    preload_flinch( t_combat_creature& creature, 
		                                       t_direction direction );
	bool						read( std::streambuf& buffer );
	void                        remove( t_combat_creature* actor );
	void						remove_creature_label( t_abstract_combat_object* object );
	void						remove_gate( t_stationary_combat_object* object );
	void	 					remove_movement_shading();
	void						remove_object( t_object_ptr object_ptr );
	void					    remove_threat( t_combat_creature* actor );
	void						remove_viewer( t_battlefield_window* viewer );
	void						removed( t_attackable_obstacle* obstacle );
	void                        resolve_attacks();
	void                        right_click( t_screen_point const& screen_point );
	void						right_click_dialog_closed();
	void                        select_next_creature();
	void						select_target( t_combat_creature* creature );
	void						select_targets( t_combat_creature_list const& targets );
	void					    select_targets( t_map_point_2d const& center, int radius );
	void						set_auto_combat( bool local, bool val );
	void                        set_buttons();
	void						set_combat_window( t_combat_window* window );
	void						set_creature_drawing_order( t_combat_creature& creature );
	void                        set_cursor_mode( t_combat_cursor_mode mode );
	void						set_current_action( t_actor&					actor,
													t_combat_actor_action_id	new_action_id,
													int							new_frame_num = 0 );
	void						set_current_direction( t_actor&    actor,
													   t_direction new_direction );
	void						set_current_direction_and_action(
										t_actor&					actor,
										t_direction					new_direction,
										t_combat_actor_action_id	new_action_id,
										int							new_frame_num = 0 );
	void						set_current_frame_num( t_actor& actor,
													   int	    new_frame_num );
	void						set_drawing_order( t_object& object );
	void						set_movement_shading( t_combat_creature const& center );
	void					    set_movement_shading_to_default();
	void                        set_influences();
	void						set_passability( t_battlefield_preset_map_in_game const * passability_map );
	void						set_retreat_checked( bool side, bool arg = true );
	void                        set_spell( t_combat_spell_ptr spell );
	bool						show_bad_morale();
	void						show_breath_targets( t_combat_creature&	   attacker,
											            t_attackable_object&   defender,
														t_screen_point const&  screen_point );
	bool						show_good_morale();
	void						show_multi_attack_targets( t_combat_creature&	attacker,
															  t_attackable_object&	defender,
															  t_screen_point const&	screen_point );
	void				        start_animation( t_combat_creature&					creature, 
												 t_spell							spell,
 												 t_combat_action_message const &	message );
	void					    start_animation( t_combat_creature&					creature, 
												 t_spell							spell,
									             t_window_handler					end_handler,
 												 t_combat_action_message const &	message );
	void                        start_damage_spell( t_combat_creature_ptr caster,
													t_combat_creature&				creature, 
													int								damage,
		                                            t_spell							spell,
													t_combat_action_message const &	message );
	void				        start_pre_action_animation( t_combat_creature&				creature,
		                                                    t_spell							spell,
 															t_combat_action_message const &	message );
	t_screen_point				subcell_to_screen_point( t_map_point_3d const & point ) const;
	void						surrender(); // currently active side surrenders.
	void						stamp( t_object*				 object, 
		                               t_combat_footprint const& footprint,
									   t_map_point_2d const&	 point );
	void						unstamp( t_object*				   object, 
		                                 t_combat_footprint const& footprint,
										 t_map_point_2d const&	   point );
	void						update_state();
	void						use_town_gate();
	void                        wait_action();
	bool						write( std::streambuf& buffer ) const;

protected:
	enum { k_melee_cursor_count = 16 };

	void					    begin_area_effect_attack( t_combat_creature&	attacker, 
											              t_map_point_3d const& target_center,
														  bool					is_retaliation );
	void						begin_melee_attack( t_combat_creature&		 attacker, 
												    t_attackable_object&	 defender,
												    bool					 flinch,
												    bool					 is_retaliation );
	void                       begin_melee_retaliation();
	void					   begin_ranged_attack( t_combat_creature&	  attacker, 
										            t_map_point_3d const& target_center,
													bool				  is_retaliation );
	void					   begin_ranged_attack( t_combat_creature&	  attacker, 
										            t_combat_creature&	  defender,
													bool				  is_retaliation );
	void					   begin_ranged_retaliation();
	void					   begin_spell( t_direction               direction,
											t_combat_creature_handler handler,
											t_combat_creature_handler end_handler,
											t_combat_action_message const & message );
	void					   begin_throw_potion( t_direction direction );
	t_combat_flinch*		   check_breath( t_combat_creature&				 attacker,
								             t_attackable_object&			 defender, 
								             t_combat_flinch*				 flinch,
											 t_combat_action_message const & message );
	bool					   check_regeneration( t_combat_creature& creature );
	void                       choose_action();
	void					   choose_berserk_melee_action();
	void					   choose_berserk_ranged_action();
	void					   clear();
	void					   create_missile( t_combat_creature& actor, 
		                                       t_map_point_3d	  target_center,
											   bool				  is_retaliation );
	void					   end_ranged_attack( int attacks_left );
	void					   end_melee_attack( int attacks_left );
	void                       end_pre_action_animation( t_window* window, t_combat_creature& );
	void					   end_strike_and_return( t_combat_creature& creature, 
		                                              t_direction direction );
	void					   execute_attack( t_combat_creature& actor );
	int						   get_move_cursor_turns_to_point( t_combat_creature const & creature,
														       t_map_point_2d const & point ) const;
	int						   get_ranged_damage( t_combat_creature const& attacker,
									              t_combat_creature const& defender ) const;
	t_map_point_2d			   get_waypoint( t_map_point_2d const& point ) const;
	void					   initialize();
	void                       initialize_morale();
	t_combat_creature_handler  multi_attack( t_combat_creature&					attacker,
							                 t_attackable_object&				defender,
										     bool								flinch,
											 t_combat_action_message const &	message);
	void					   place_castle( t_combat_castle const&						castle,
											 t_combat_object_model_cache_array const&	caches );
	bool					   raw_cell_hit_test( t_rational_point const & point, 
		                                          t_map_point_2d & result ) const;
	bool					   raw_cell_hit_test( t_screen_point const& screen_point,
											      t_map_point_2d&		 cell_point ) const;
	void					   remove_drift_window( t_window* window );
	void                       select( t_combat_creature& creature, bool arg = true );
	t_combat_creature*		   select_next_creature( bool last_was_defender );
	bool					   set_acting( t_combat_creature* actor );
	void					   set_cursor_frame( t_map_point_2d const& point, 
									             t_bitmap_cursor& cursor ) const;
	void					   set_forbidden_cells();
	void					   set_preset_passability_maps(
									std::vector<t_battlefield_preset_map_in_game_ptr> const& battlefield_preset_map_vector);
	void					   set_transparency();
	bool						shackles_of_war_present( std::string*		text ) const;
	void					   update_morale();
	void					   update_retaliation();


	typedef t_isometric_map<t_cell>									t_cell_map;
	typedef t_isometric_vertex_map<t_cell_vertex>					t_vertex_map;
	typedef std::list<t_handler>									t_action_list;
	typedef std::list<t_attack>										t_attack_list;
	typedef t_owned_ptr< t_combat_non_blocking_message_displayer >	t_non_blocking_message_displayer_ptr;

	// Data members
	t_creature_ptr							m_acting_creature;
	t_combat_creature const*				m_acting_creature_reported;
	t_creature_array*						m_armies[2];
	t_attackable_obstacle_list				m_attackable_obstacles;
	t_attack_list							m_attacks;
	bool									m_auto_combat_flags[2];
	int										m_base_height;  // height of "flat" terrain
	t_bitmap_cursor							m_blocked_cursor;
	int										m_castle_inside_row;
	t_town_image_level						m_castle_level;
	int										m_castle_row;
	t_cell_map								m_cell_map;
	t_vertex_map							m_cell_vertex_map;
	t_counted_ptr<t_combat_window>			m_combat_window;
	t_object_ptr_list						m_creature_label_list;
	t_creature_list							m_creature_list;
	t_combat_cursor_mode					m_current_cursor_mode;
	t_creature_const_ptr					m_current_movement_shaded_creature;
	t_combat_user_action_ptr				m_current_user_action;
	mutable t_ai_combat_data_cache			m_data_cache;
	t_combat_spell_ptr						m_default_spell;
	t_non_blocking_message_displayer_ptr	m_defend_wait_displayer;
	bool									m_defender_retaliated;
	int										m_distance_moved;
	t_timed_window_list						m_drift_windows;
	t_combat_creature_handler				m_end_animation_handler;
	bool									m_fled[2];
	t_creature_list							m_fled_stacks;
	t_bitmap_cursor							m_fly_cursor;
	t_castle_gate_ptr						m_gate;
	t_owned_ptr<t_cached_grail_data_source>	m_grail_data[2];
	std::string								m_help_text;
	t_bitmap_cursor							m_info_cursor;
	bool									m_is_at_sea;
	t_creature_ptr							m_last_target;
	bool									m_last_was_defender;
	t_bitmap_cursor							m_melee_cursor[k_melee_cursor_count];
	int										m_morale_modifier[2];
	t_combat_area_shader_ptr				m_movement_shader;
	t_timed_callback						m_movement_shading_resetter;
	long									m_next_battlefield_id;
	t_bitmap_cursor							m_normal_cursor;
	t_object_ptr_list						m_object_ptr_list;
	int										m_original_hit_points[2];
	t_action_list							m_pending_actions;
	t_player*								m_players[2];
	t_handler								m_resolve_handler;
	bool									m_retreat_checked[2];
	t_counted_animation_list				m_running_animation_list;
	int										m_running_animations;
	t_creature_list					m_selected_creatures;
	t_sequence_loader				m_sequence_loader;
	t_bitmap_cursor					m_shoot_cursor;
	t_combat_spell_ptr				m_spell;
	t_bitmap_cursor					m_spell_cannot_cast_cursor;
	t_mouse_window_ptr				m_spell_cursor;
	t_animation_ptr					m_spell_cursor_animation;
	t_map_point_2d					m_starting_position;
	t_combat_state					m_state;
	t_combat_object_ptr				m_target;
	t_map_point_3d					m_target_subcell;
	t_bitmap_cursor					m_tower_move_cursor;
	t_town const*					m_town;
	int								m_turn_number;
	t_battlefield_view_size_id		m_view_size_id;
	t_battlefield_window*			m_viewer_ptr;
	t_bitmap_cursor					m_walk_cursor;
	t_stationary_combat_object_list	m_wall_objects;
};

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline void t_battlefield::add_viewer( t_battlefield_window * new_viewer_ptr )
{
	m_viewer_ptr = new_viewer_ptr;
}

inline t_stationary_combat_object_iterator t_battlefield::castle_begin() 
{
	return m_wall_objects.begin();
}

inline t_stationary_combat_object_const_iterator t_battlefield::castle_begin() const
{
	return m_wall_objects.begin();
}

inline t_stationary_combat_object_iterator t_battlefield::castle_end()
{
	return m_wall_objects.end();
}

inline t_stationary_combat_object_const_iterator t_battlefield::castle_end() const
{
	return m_wall_objects.end();
}

inline t_creature_array** t_battlefield::get_armies()
{
	return m_armies;
}

inline t_town_image_level t_battlefield::get_castle_level() const
{
	return m_castle_level;
}

inline t_combat_cursor_mode t_battlefield::get_preferred_action() const
{
	return m_current_cursor_mode;
}

inline bool t_battlefield::get_retreat_checked( bool side ) const
{
	return m_retreat_checked[side];
}

inline t_battlefield_window* t_battlefield::get_window() const
{
	return m_viewer_ptr;
}

inline int t_battlefield::get_base_height() const
{
	return m_base_height;
}

inline int t_battlefield::get_castle_row() const
{
	return m_castle_row;
}

inline t_player** t_battlefield::get_players()
{
	return m_players;
}

inline t_combat_state t_battlefield::get_state() const
{
	return m_state;
}

inline bool t_battlefield::is_valid( t_map_point_2d const& point ) const
{
	return m_cell_map.is_valid( point );
}


// -----------------------------------------------------------------------
// Adjust damage for a charging creature. Static function
// -----------------------------------------------------------------------
inline void t_battlefield::adjust_for_charging_bonus(int &damage, int distance_moved)
{
	if (distance_moved > 500)
	{
		damage = damage * (85 + distance_moved * 10 / 350 ) / 100;
	}
}
 
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline void t_battlefield::place_object( t_object_ptr			object_ptr,
										 t_map_point_2d const &	position )
{
	int height = compute_terrain_height_under_object( *object_ptr, position );
	place_object( object_ptr, t_map_point_3d( position, height ) );
}

inline void	t_battlefield::move_object( t_object&             object,
										t_map_point_2d const& new_position )
{
	int height = compute_terrain_height_under_object( object, new_position );
	
	move_object( object, t_map_point_3d( new_position, height ) );
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline t_battlefield::t_cell &
t_battlefield::get_cell( t_map_point_2d const & cell_point )
{
	return m_cell_map.get( t_level_map_point_2d( cell_point, 0 ) );
}

inline int t_battlefield::get_row_end( int row ) const
{
	return m_cell_map.get_row_end( row );
}

inline int t_battlefield::get_row_start( int row ) const
{
	return m_cell_map.get_row_start( row );
}

inline t_animation_ptr t_battlefield::get_spell_cursor_animation() const
{
	return m_spell_cursor_animation;
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline t_battlefield::t_cell const &
t_battlefield::get_cell( t_map_point_2d const & cell_point ) const
{
	return m_cell_map.get( t_level_map_point_2d( cell_point, 0 ) );
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline int t_battlefield::get_cell_row_end( int row ) const
{
	return m_cell_map.get_row_end( row );
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline int t_battlefield::get_cell_row_start( int row ) const
{
	return m_cell_map.get_row_start( row );
}


// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline t_battlefield::t_cell_vertex &
t_battlefield::get_cell_vertex( t_map_point_2d const & vertex_point )
{
	return m_cell_vertex_map.get( t_level_map_point_2d( vertex_point, 0 ) );
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline t_battlefield::t_cell_vertex const &
t_battlefield::get_cell_vertex( t_map_point_2d const & vertex_point ) const
{
	return m_cell_vertex_map.get( t_level_map_point_2d( vertex_point, 0 ) );
}

inline t_castle_gate_ptr t_battlefield::get_gate() const
{
	return m_gate;
}

inline std::string t_battlefield::get_help_text() const
{
	return m_help_text;
}

// -----------------------------------------------------------------------
// get a logical point from actual screen coordinates
// -----------------------------------------------------------------------
inline t_rational_point t_battlefield::get_logical_point( t_screen_point const& point ) const
{
	// Scale the point to logical battlefield view coordinates
	t_rational_point const & view_ratio = get_view_ratio();

	return t_rational_point( point.x / view_ratio.x, point.y / view_ratio.y );
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline int t_battlefield::get_size() const
{
	return m_cell_map.get_size();
}


// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline void t_battlefield::remove_viewer( t_battlefield_window* viewer )
{
	if (m_viewer_ptr == viewer)
		m_viewer_ptr = 0;
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline t_combat_object_iterator t_battlefield::objects_begin()
{
	return m_object_ptr_list.begin();
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline t_combat_object_const_iterator t_battlefield::objects_begin() const
{
	return m_object_ptr_list.begin();
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline t_combat_object_iterator t_battlefield::objects_end()
{
	return m_object_ptr_list.end();
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline t_combat_object_const_iterator t_battlefield::objects_end() const
{
	return m_object_ptr_list.end();
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
inline t_screen_point t_battlefield::get_cell_vertex_screen_point( 
					  t_map_point_2d const& vertex_point ) const
{
	int vertex_height = get_cell_vertex( vertex_point ).get_height();

	return cell_to_screen_point( t_map_point_3d( vertex_point, vertex_height ) );
}

// -----------------------------------------------------------------------
// get cell from raw screen point
// -----------------------------------------------------------------------
inline bool t_battlefield::raw_cell_hit_test( t_screen_point const & point, t_map_point_2d & result ) const
{
	return raw_cell_hit_test( get_logical_point( point ), result );
}

inline t_combat_creature_iterator t_battlefield::creatures_begin()
{
	return m_creature_list.begin();
}

inline t_combat_creature_iterator t_battlefield::creatures_end()
{
	return m_creature_list.end();
}

inline int t_battlefield::creatures_size() const
{
	return m_creature_list.size();
}

inline bool t_battlefield::is_sea_battle() const
{
	return m_is_at_sea;
}

inline t_map_point_3d t_battlefield::get_cell_center( t_map_point_2d const& cell_point ) const
{
	t_map_point_3d result( ::get_cell_center( cell_point ), 0 );

	result.height = compute_terrain_height( result );
	return result;
}

inline void t_battlefield::set_spell( t_combat_spell_ptr spell )
{
	m_spell = spell;
}

// Returns the AI's data cache
inline t_ai_combat_data_cache & t_battlefield::get_data_cache() const
{
	return m_data_cache;
}

// Returns the combat path finder for the currently active unit
inline t_combat_path_finder& t_battlefield::get_current_path_finder() const
{
	return m_acting_creature->get_path_finder();
}

inline void t_battlefield::set_retreat_checked( bool side, bool arg )
{
	m_retreat_checked[side] = arg;
}


#endif // !defined( BATTLEFIELD_H_INCLUDED )
